<?php

/**
 * CelebrioPeople Person
 *
 * @copyright  Copyright (c) 2011 Celebrio Software
 * @package    CelebrioPeople
 */
namespace ApplicationsModule\PeopleModule;

use \Nette\Object;
use \Nette\Reflection\ClassReflection;

use \dibi;

use \Celebrio\AccessControl\UserManagement;
use \Celebrio\AccessControl\BaseUser;

use \Celebrio\Core\ServiceProvider;
use \Celebrio\Modules;

/**
 * Person entity
 *
 * @author Celebrio Software
 */
class Person extends BaseUser {

    /** @var int */
    private $person_id = 0;

    /** @var AlbireoUser **/
    private $user = NULL;

    /** @var string URL **/
    private $photo_person = "";

    /** @var array */
    private $additional_info = array();

    /**
     * Person entity
     *
     * @author Celebrio Software
     *
     * @param string $first_name
     * @param string $last_name
     * @param url $profile_picture
     * @param int $user_id
     */
    public function __construct($first_name = NULL, $last_name = NULL, $profile_picture = NULL, $user_id = NULL) {
        $this->setUserId($user_id);
        $this->setFirstName($first_name);
        $this->setLastName($last_name);
        $this->setProfilePicture($profile_picture);
    }

    /**
     * @static
     * @param array $values
     * @return Person
     */
    public static function fromValues($values) {

        // set the base values
        $file = $values["photo_person"];
        if ($file->isImage()) {
            $filename = $file->getTemporaryFile();
            //TODO save image
        } elseif(!empty($values["photo_person_hidden"])) {
            $filename = $values["photo_person_hidden"];
        } else {
            $filename = null;
        }

        $first_name = $values["first_name_person"];
        $last_name = $values["last_name_person"];
        $person = new self($first_name, $last_name, $filename);

        // remove already used values
        foreach (PeopleItems::providedRows(array()) as $base_item) {
            unset($values[$base_item["db"]]);
        }

        // set all additional info (items from contact modules)
        foreach ($values as $additional_key => $additional_val) {
            $person->addToAdditionalInfo($additional_key, $additional_val);
        }

        return $person;
    }

    public function getId() {
        return $this->person_id;
    }

    public function setId($id) {
        $this->person_id = $id;
    }

    public function getProfilePicture() {
        return $this->photo_person;
    }

    public function setProfilePicture($profile_picture) {
        $this->photo_person = $profile_picture;
    }

    public function getEmails() {
        $services = ServiceProvider::getAllServices(Modules::CONTACTS);
        $mails = array();
        foreach ($services as $service) {
            $serviceMails = $service->getMail($this->getId());
            if ($serviceMails !== DummyContactService::NOT_PROVIDED) {
                $mails = array_merge($mails, $serviceMails);
            }
        }
        return $mails;
    }

    /**
     * gets AlbireoUser object containing a Celebrio user entity
     * lazy getter - object is loaded at the time of calling this method
     *
     * @return AlbireoUser or null when the user does not exist
     */
    public function getUser() {
        if ($this->user === NULL) {
            $userManager = new UserManagement();
            $this->user = $userManager->getUser($this->getUserId());
            unset($userManager);
        }
        return $this->user;
    }

    /**
     * @return array
     */
    public function getAdditionalInfo() {
        return $this->additional_info;
    }

    public function addToAdditionalInfo($key, $value) {
        if ($value === null) return;
        if (isset($this->additional_info[$key])) {
            if (!in_array($value, $this->additional_info[$key])) {
                array_push($this->additional_info[$key], $value);
            }
        } else {
            $this->additional_info[$key] = array($value);
        }
    }

    public function clearAdditionalInfo() {
        $this->additional_info = array();
    }


    public function getInfoField($key, $compact = true) {
        $reflector = new ClassReflection($this);
        if ($reflector->hasProperty($key)) {
            return $this->$key;
        } elseif (isset($this->additional_info[$key])) {
            $item = $this->additional_info[$key];
            if ($compact) {
                return $item[0];
            } else {
                return $item;
            }
        } else {
            return null;
        }
    }

    /**
     * This method is for connecting person to the user - the same contact. This does NOT
     * mean connecting in the friendship manner.
     *
     * @throws \Exception
     * @param null $user_id
     * @return void
     */
    public function connectToUser($user_id = null) {
        if ($user_id === null) {
            $user_id = $this->getUserId();
            if ($user_id === null) {
                throw new \Exception("Trying to connect Person without assigned user ID.");
            }
        }
        $already_assigned = dibi::select("id_person")->from("users")->where(array("id" => $user_id))->fetch();
        if ($already_assigned->id_person !== null ) {
            throw new \Exception("User with id $user_id has already been assigned to person.");
        }
        dibi::update("users", array("id_person" => $this->getId()))
                ->where(array("id" => $user_id))
                ->execute();
    }

    public function to_a() {
        $person_array = array(
            "id" => $this->getId(),
            "first_name" => $this->getFirstName(),
            "last_name" => $this->getLastName(),
            "profile_picture" => $this->getProfilePicture(),
            "additional_info" => $this->getAdditionalInfo(),
        );
        return $person_array;
    }

    public static function more_to_a(array $people) {
        return array_map(
            function(Person $person) {
                return $person->to_a();
            },
            $people
        );
    }
}